package com.nts.pmchelperdemo3.util;

import org.springframework.util.Assert;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;

/**
 * 日期时间工具类（核心：计算工作时间、处理非工作时段）
 * 工作规则：每日8:30-19:00，每周工作6天（周一至周六，周日休息）
 */
public class DateUtil {

    /**
     * 计算工作时间结束时间（排除非工作时段和周日）
     * @param startTime 任务开始时间
     * @param workHours 需工作的小时数
     * @param workStart 每日工作开始时间（如"08:30"）
     * @param workEnd 每日工作结束时间（如"19:00"）
     * @return 任务结束时间
     */
    public static LocalDateTime calculateWorkEndTime(LocalDateTime startTime, double workHours,
                                                     String workStart, String workEnd) {
        Assert.notNull(startTime, "开始时间不能为空");
        Assert.isTrue(workHours >= 0, "工作时长不能为负数");

        LocalTime dailyStart = LocalTime.parse(workStart);
        LocalTime dailyEnd = LocalTime.parse(workEnd);
        LocalDateTime current = startTime;
        double remainingHours = workHours;

        // 若开始时间在非工作时间，先调整到下一个工作时间点
        current = adjustToWorkTime(current, dailyStart, dailyEnd);

        while (remainingHours > 0) {
            // 检查当前日期是否为周日（休息日）
            if (current.getDayOfWeek() == DayOfWeek.SUNDAY) {
                current = current.plusDays(1).with(dailyStart); // 跳到下周一上班时间
                continue;
            }

            // 计算当天剩余工作时间（小时）
            LocalTime currentTime = current.toLocalTime();
            double hoursLeftToday;

            if (currentTime.isBefore(dailyStart)) {
                // 当天尚未开始工作，从上班时间算起
                hoursLeftToday = ChronoUnit.MINUTES.between(dailyStart, dailyEnd) / 60.0;
                current = current.with(dailyStart); // 调整到上班时间
            } else if (currentTime.isAfter(dailyEnd)) {
                // 当天工作已结束，跳到下一个工作日
                current = current.plusDays(1).with(dailyStart);
                continue;
            } else {
                // 当天工作中，计算剩余时间
                hoursLeftToday = ChronoUnit.MINUTES.between(currentTime, dailyEnd) / 60.0;
            }

            // 分配工作时长
            if (remainingHours <= hoursLeftToday) {
                // 当天可完成
                current = current.plusMinutes((long) (remainingHours * 60));
                remainingHours = 0;
            } else {
                // 当天无法完成，消耗全天工作时间
                remainingHours -= hoursLeftToday;
                current = current.plusDays(1).with(dailyStart); // 跳到下一个工作日
            }
        }

        return current;
    }

    /**
     * 在工作时间基础上增加指定小时数（用于计算调试时间等）
     * @param time 基准时间
     * @param hours 增加的小时数
     * @param workStart 每日工作开始时间
     * @param workEnd 每日工作结束时间
     * @return 增加后的时间（仅在工作时间内累加）
     */
    public static LocalDateTime addWorkHours(LocalDateTime time, int hours,
                                             String workStart, String workEnd) {
        return calculateWorkEndTime(time, hours, workStart, workEnd);
    }

    /**
     * 将时间调整到最近的工作时间（若在非工作时间则跳到下一个工作时间点）
     * @param time 待调整时间
     * @param dailyStart 每日工作开始时间
     * @param dailyEnd 每日工作结束时间
     * @return 调整后的工作时间
     */
    private static LocalDateTime adjustToWorkTime(LocalDateTime time, LocalTime dailyStart, LocalTime dailyEnd) {
        LocalDateTime adjusted = time;

        // 处理当天非工作时间
        if (adjusted.toLocalTime().isBefore(dailyStart)) {
            adjusted = adjusted.with(dailyStart); // 当天尚未上班，调整到上班时间
        } else if (adjusted.toLocalTime().isAfter(dailyEnd)) {
            adjusted = adjusted.plusDays(1).with(dailyStart); // 当天已下班，调整到次日上班时间
        }

        // 处理周日（休息日）
        if (adjusted.getDayOfWeek() == DayOfWeek.SUNDAY) {
            adjusted = adjusted.plusDays(1).with(dailyStart); // 跳到下周一上班时间
        }

        return adjusted;
    }

    /**
     * 计算两个时间之间的工作日天数（扣除周日和非工作时段）
     * @param start 开始时间
     * @param end 结束时间
     * @return 工作日天数
     */
    public static long getWorkDayCount(LocalDateTime start, LocalDateTime end) {
        if (start.isAfter(end)) {
            return 0;
        }

        long days = 0;
        LocalDateTime current = start;
        while (current.isBefore(end)) {
            if (current.getDayOfWeek() != DayOfWeek.SUNDAY) { // 排除周日
                days++;
            }
            current = current.plusDays(1);
        }
        return days;
    }
}
